
import { BaseState, StateMachine } from "../base/fsm";
import PoolManager from "../manager/PoolManager";
import { FlashDamageBuff, Effect, EffectMethod } from "./BuffManager";
import { AStar } from "./findpath/AStar";
import Unit from "./Unit";
import Bullet_Tracking from "./view/Bullet_Tracking";

export const UnitStateEnum = {
    Attack: 'Attack',
    FindAim: 'FindAim',
    Idle: 'Idle',
    MoveToAim: 'MoveToAim',
    Death: 'Death',
}

export class UnitState extends BaseState<Unit>{
    public fsm: UnitStateMachine;
    public constructor(fsm: UnitStateMachine) {
        super();
        this.fsm = fsm;
    }
    public onEnter(...args) {
    }
    public onUpdate(dt: any) {
    }
    public onQuit() {
    }

}

export class AttackState extends UnitState {
    public buff: FlashDamageBuff;
    public count: number = 0;
    public qianyao: number = 0.1;
    public canPlay = true;
    public onEnter() {
        this.count = 0;
        this.canPlay = true;
        this.buff = new FlashDamageBuff();
        let self = this.fsm.Onwer;
        this.buff.fromUnit = self;
        this.buff.targatUnit = this.fsm.aim;

        this.buff.effect = new Effect();
        this.buff.effect.method = EffectMethod.Reduce;
        this.buff.effect.data = {
            currentHp: this.fsm.Onwer.getProperty('atk'),
        }
        let direction = this.fsm.aim.gridPos.sub(self.gridPos);
        if (direction.x > 0)
            direction.x = 1;
        else if (direction.x < 0)
            direction.x = -1;
        if (direction.y > 0)
            direction.y = 1;
        else if (direction.y < 0)
            direction.y = -1;
        self.direction = direction;
    }
    public attck() {
        //console.log('addBuff');
        this.fsm.aim.buffManager.addBuff(this.buff);
    }
    public onUpdate() {
        let attackTimeing = this.count / this.fsm.Onwer.getProperty('atk_speed');
        if (this.fsm.CurrentStateTime >= attackTimeing) {
            let self = this.fsm.Onwer;
            if (!this.fsm.aim.isDeath()) {
                let direction = self.gridPos.sub(this.fsm.aim.gridPos);
                let distance = direction.len();
                let attackDistance = self.getProperty('atk_range');
                if (distance > attackDistance) {
                    self.changeState(UnitStateEnum.FindAim);
                    return;
                }
                if (this.canPlay) {
                    self.anim.play('A');
                    this.canPlay = false;
                }
                if (this.fsm.CurrentStateTime >= attackTimeing + this.qianyao) {
                    this.canPlay = true;
                    this.attck();
                    ++this.count;
                }
            } else {
                self.changeState(UnitStateEnum.FindAim);
            }
        }

    }
}
export class LongRangeAttack extends AttackState {
    public async attck() {
        //this.fsm.aim.buffManager.addBuff(this.buff);
        let name = this.fsm.Onwer.getProperty('bullet');
        let parent = cc.find('Canvas/mapEffect');
        let bullet = await PoolManager.instance.get(name);
        
        parent.addChild(bullet);
        bullet.setPosition(this.fsm.Onwer.node.position);

        bullet.getComponent(Bullet_Tracking).fire(this.fsm.aim, () => {
            if (!this.fsm.aim) {
                return;
            }
            if (!this.fsm.aim.isDeath()) {
                this.fsm.aim.buffManager.addBuff(this.buff);
            }
        });
    }
}
export class FindAim extends UnitState {
    public onEnter() {
        this.onUpdate = null;
        this.onQuit = null;
        let self = this.fsm.Onwer;
        this.fsm.aim = self.world.getNearestUnit(self);
        if (!this.fsm.aim) {
            self.changeState(UnitStateEnum.Idle);
            return;
        }
        let attackDistance = self.getProperty('atk_range');
        let direction = self.gridPos.sub(this.fsm.aim.gridPos);
        if (direction.len() <= attackDistance) {
            self.changeState(UnitStateEnum.Attack);
            return;
        }
        self.changeState(UnitStateEnum.MoveToAim);

    }
}
export class IdeState extends UnitState {
    public onEnter() {
        let self = this.fsm.Onwer;
        self.anim.play('S');
        //console.log('S');

    }
}
export class MoveToAim extends UnitState {
    aimpos: cc.Vec2
    public onEnter() {
        let self = this.fsm.Onwer;
        this.aimpos = this.fsm.aim.gridPos;
        AStar.instance.queue.push(self.moveComponent.move.bind(self.moveComponent, this.aimpos.x, this.aimpos.y));
        //self.moveComponent.move(this.aimpos.x, this.aimpos.y);

    }


}
export class DeathState extends UnitState {
    public onEnter() {

        this.fsm.Onwer.clear();
    }
}
//let statetype = { AttackState, IdeState, DeathState, FindAim }
export default class UnitStateMachine extends StateMachine<Unit>{

    //public aims: Unit[] = [];

    public aim: Unit = null;
    constructor(owner: Unit) {
        super();
        this.Onwer = owner;
        this.Onwer.fsm = this;
        this.states.set(UnitStateEnum.MoveToAim, new MoveToAim(this));
        if (this.Onwer.getProperty('atk_range') >= 2) {
            this.states.set(UnitStateEnum.Attack, new LongRangeAttack(this));
        } else
            this.states.set(UnitStateEnum.Attack, new AttackState(this));
        this.states.set(UnitStateEnum.Idle, new IdeState(this));
        this.states.set(UnitStateEnum.Death, new DeathState(this));
        this.states.set(UnitStateEnum.FindAim, new FindAim(this));
    }

    public stop() {
        super.stop();
        this.aim = null;
    }
}